package com.lmaye.utils;

import com.lmaye.common.ErrorInfo;
import com.lmaye.exceptions.CommonException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 查询工具类
 *
 * @author lmay.Zhou
 * @date 2019/4/23 17:09 星期二
 * @qq 379839355
 * @email lmay@lmaye.com
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class RequestUtils {
    /**
     * 序列化字段名
     */
    private static final String SERIAL_VERSION_UID = "serialVersionUID";

    /**
     * 获取查询条件的方法
     *
     * @param param
     * @return
     * @throws Exception
     */
    @SuppressWarnings("Duplicates")
    public static HashMap<String, Object> getParams(Object param) {
        HashMap<String, Object> values = new HashMap<>(16);
        //父类属性
        Class<?> superClass = param.getClass().getSuperclass();
        Field[] superFields = superClass.getDeclaredFields();
        for (Field field : superFields) {
            field.setAccessible(true);
            String name = field.getName();
            if (Objects.equals(SERIAL_VERSION_UID, name)) {
                continue;
            }
            Object value = invokeSuperMethod(param, name, null);
            if (!Objects.isNull(value)) {
                values.put(name, value);
            }
        }
        //子类属性
        Class<?> aClass = param.getClass();
        Map<String, Object> childMap = new HashMap<>(16);
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String name = field.getName();
            if (Objects.equals(SERIAL_VERSION_UID, name)) {
                continue;
            }
            Object value = invokeMethod(param, name, null);
            if (!Objects.isNull(value)) {
                childMap.put(name, value);
            }
        }
        values.put("bizContent", JsonUtils.writeValueAsString(childMap));
        return values;
    }

    /**
     * 获取父类属性值的方法
     *
     * @param owner
     * @param methodName
     * @param args
     * @return
     * @throws Exception
     */
    private static Object invokeSuperMethod(Object owner, String methodName, Object[] args) {
        Class ownerClass = owner.getClass().getSuperclass();
        methodName = methodName.substring(0, 1).toUpperCase()
                + methodName.substring(1);
        return baseInvokeMethod(owner, methodName, ownerClass);
    }

    /**
     * 获取属性值的方法
     *
     * @param owner
     * @param methodName
     * @param args
     * @return
     * @throws Exception
     */
    private static Object invokeMethod(Object owner, String methodName, Object[] args) {
        Class ownerClass = owner.getClass();
        methodName = methodName.substring(0, 1).toUpperCase()
                + methodName.substring(1);
        return baseInvokeMethod(owner, methodName, ownerClass);
    }

    /**
     * 反射执行方法
     *
     * @param owner
     * @param methodName
     * @param ownerClass
     * @return
     */
    private static Object baseInvokeMethod(Object owner, String methodName, Class ownerClass) {
        try {
            Method method = ownerClass.getMethod("get" + methodName);
            return method.invoke(owner);
        } catch (Exception e) {
            throw new CommonException(ErrorInfo.error("反射执行方法失败"), e);
        }
    }

    /**
     * Map转Json
     *
     * @param requestBody
     * @return
     */
    public static String convertMapToJson(Map<String, Object> requestBody) {
        TreeSet<String> sortedKey = new TreeSet<String>(requestBody.keySet());
        StringBuilder builder = new StringBuilder();
        for (String key : sortedKey) {
            if (!Objects.equals(key, "sign")) {
                builder.append(key).append("=").append(convertObjectToJson(requestBody.get(key))).append("&");
            }
        }
        String result = builder.toString();
        return result.substring(0, result.length() - 1);
    }

    /**
     * Object转Json
     *
     * @param obj
     * @return
     */
    public static String convertObjectToJson(Object obj) {
        if (obj == null) {
            return "";
        }
        if (obj.getClass().isArray()) {
            return StringUtils.join((Object[]) obj, "&");
        } else if (obj instanceof Map) {
            return convertMapToJson((Map<String, Object>) obj);
        } else if (obj.getClass().isPrimitive() || obj.getClass() == String.class) {
            return String.valueOf(obj);
        } else if (obj instanceof Collection) {
            StringBuilder builder = new StringBuilder();
            for (Object obj_ : (Collection) obj) {
                builder.append(convertObjectToJson(obj_)).append("&");
            }
            String result = builder.toString();
            return result.substring(0, result.length() - 1);
        } else {
            return String.valueOf(obj);
        }
    }
}